from blaseball_mike.models import Team
from blaseball_mike.chronicler import BASE_URL as CHRONICLER_URL
from blaseball_mike.reference import BASE_URL as DATABLASE_URL
import requests
import pandas
from plotly.graph_objects import Figure
import plotly.io as _pio
_pio.renderers.default = "notebook_connected"
# Make a big table of team average stars in all categories over time
INVALID_TEAMS = {"Hall Stars": "c6c01051-cdd4-47d6-8a98-bb5b754f937f",
"The Shelled One's Pods": "40b9ec2a-cb43-4dbb-b836-5accb62e7c20",
"Real Game Band": "7fcb63bc-11f2-40b9-b465-f1d458692a63",
"FWXBC": "e3f90fa1-0bbe-40df-88ce-578d0723a23b",
"Club de Calf": "a3ea6358-ce03-4f23-85f9-deb38cb81b20",
"BC Noir": "f29d6e60-8fce-4ac6-8bc2-b5e3cabc5696",
"Atlético Latte": "49181b72-7f1c-4f1c-929f-928d763ad7fb",
"Cold Brew Crew": "4d921519-410b-41e2-882e-9726a4e54a6a",
"Royal PoS": "9a5ab308-41f2-4889-a3c3-733b9aab806e",
"Cream & Sugar United": "b3b9636a-f88a-47dc-a91d-86ecc79f9934",
"Pandemonium Artists": "3b0a289b-aebd-493c-bc11-96793e7216d5",
"Society Data Witches": "d2634113-b650-47b9-ad95-673f8e28e687",
"Inter Xpresso": "d8f82163-2e74-496b-8e4b-2ab35b2d3ff1",
"Milk Proxy Society": "a7592bd7-1d3c-4ffb-8b3a-0b1e4bc321fd",
"Macchiato City": "9e42c12a-7561-42a2-b2d0-7cf81a817a5e",
"Light & Sweet Electric Co.": "70eab4ab-6cb1-41e7-ac8b-1050ee12eecc",
"Americano Water Works": "4e5d0063-73b4-440a-b2d1-214a7345cf16",
"Heavy FC": "e8f7ffee-ec53-4fe0-8e87-ea8ff1d0b4a9"}
def parse_emoji(val):
try:
return chr(int(val, 16))
except ValueError:
return val
# Get all season/days and their real-life timestamps
times = requests.get(f'{CHRONICLER_URL}/time/map').json()
times = list(filter(lambda x: x['type'] in ('season', 'postseason'), times["data"]))
# Get a list of all the teams we care about
teams = Team.load_all().values()
teams = [x for x in teams if x.id not in INVALID_TEAMS.values()]
# Pull the team info for each timestamp & calculate average stars
try:
table = pandas.read_csv("team_star_changes.csv", index_col=0)
except FileNotFoundError:
table = pandas.DataFrame()
for element in times:
# If season/day already exists in the table, dont do it again
if table.size != 0:
existing_data = table[table["season"] == element["season"]+1]
existing_data = existing_data[existing_data["day"] == element["day"]+1]
if existing_data.size > 0:
continue
data = requests.get(f"{DATABLASE_URL}/allPlayersForGameday?season={element['season']}&day={element['day']}").json()
temp_table = pandas.DataFrame(data)
for team in teams:
# Filter out players on this team
players = temp_table[temp_table["team_id"] == team.id]
if players.size <= 0:
bat_avg = 0.0
pitch_avg = 0.0
base_avg = 0.0
def_avg = 0.0
else:
lineup = players[players["position_type"] == "BATTER"]
rotation = players[players["position_type"] == "PITCHER"]
lineup_no_shelled = lineup[~lineup["modifications"].astype(str).str.contains("SHELLED")]
rotation_no_shelled = rotation[~rotation["modifications"].astype(str).str.contains("SHELLED")]
bat_avg = lineup_no_shelled["batting_stars"].astype(float).mean()
pitch_avg = rotation_no_shelled["pitching_stars"].astype(float).mean()
base_avg = lineup_no_shelled["baserunning_stars"].astype(float).mean()
def_avg = lineup["defense_stars"].astype(float).mean()
table = table.append({"team": team.nickname, "emoji": parse_emoji(team.emoji), "color": team.main_color,
"batting": bat_avg, "pitching": pitch_avg, "baserunning": base_avg, "defense": def_avg,
"day": element["day"]+1, "season": element["season"]+1}, ignore_index=True)
# Incrementally save the result to a CSV
table.to_csv("team_star_changes.csv", na_rep="0.0")
# Plot it
fig_dict = {
"data": [],
"layout": {},
"frames": []
}
# Make the graph layout & fancy play/pause buttons
fig_dict["layout"]["title"] = "Average Stars over Time"
fig_dict["layout"]["xaxis"] = {"range": [1, 4.5], "title": "Batting Stars"}
fig_dict["layout"]["yaxis"] = {"range": [0, 4.5], "title": "Pitching Stars"}
fig_dict["layout"]["hovermode"] = "closest"
fig_dict["layout"]["updatemenus"] = [
{
"buttons": [
{
"args": [None, {"frame": {"duration": 250, "redraw": False},
"fromcurrent": True, "transition": {"duration": 250, "easing": "quadratic-in-out"}}],
"label": "▶",
"method": "animate"
},
{
"args": [[None], {"frame": {"duration": 0, "redraw": False},
"mode": "immediate", "transition": {"duration": 0}}],
"label": "⏸",
"method": "animate"
}
],
"direction": "left",
"pad": {"r": 10, "t": 87},
"showactive": False,
"type": "buttons",
"x": 0.1,
"xanchor": "right",
"y": 0,
"yanchor": "top"
}
]
sliders_dict = {
"active": 0,
"yanchor": "top",
"xanchor": "left",
"currentvalue": {
"font": {"size": 14},
"visible": True,
"xanchor": "right"
},
"transition": {"duration": 250, "easing": "cubic-in-out"},
"pad": {"b": 10, "t": 50},
"len": 0.9,
"x": 0.1,
"y": 0,
"steps": []
}
# Add data
first = True
for season in table["season"].unique():
subset = table[table["season"] == season]
for day in subset["day"].unique():
frame = {"data": [], "name": f"Season {int(season)}, Day {int(day)}"}
dayset = subset[subset["day"] == day]
for team in dayset["team"].unique():
teamset = dayset[dayset["team"] == team]
data_dict = {
"x": list(teamset["batting"]),
"y": list(teamset["pitching"]),
"mode": "markers+text",
"marker": {
"color": teamset["color"],
"size": 36,
"opacity": 1,
},
"name": team,
"text": teamset["emoji"],
"textposition": "middle center",
"textfont_size": 20
}
if first:
fig_dict["data"].append(data_dict)
frame["data"].append(data_dict)
fig_dict["frames"].append(frame)
slider_step = {
"args": [
[frame["name"]],
{
"frame": {"duration": 250, "redraw": False},
"mode": "immediate",
"transition": {"duration": 250}
}
],
"label": frame["name"],
"method": "animate"
}
sliders_dict["steps"].append(slider_step)
first = False
fig_dict["layout"]["sliders"] = [sliders_dict]
fig = Figure(fig_dict)
fig.show()
# Do Defense & Baserunning too
fig_dict["layout"]["xaxis"] = {"range": [1.5, 4.5], "title": "Defense Stars"}
fig_dict["layout"]["yaxis"] = {"range": [1, 5], "title": "Baserunning Stars"}
fig_dict["data"] = []
fig_dict["frames"] = []
sliders_dict["steps"] = []
first = True
for season in table["season"].unique():
subset = table[table["season"] == season]
for day in subset["day"].unique():
frame = {"data": [], "name": f"Season {int(season)}, Day {int(day)}"}
dayset = subset[subset["day"] == day]
for team in dayset["team"].unique():
teamset = dayset[dayset["team"] == team]
data_dict = {
"x": list(teamset["defense"]),
"y": list(teamset["baserunning"]),
"mode": "markers+text",
"marker": {
"color": teamset["color"],
"size": 36,
"opacity": 1,
},
"name": team,
"text": teamset["emoji"],
"textposition": "middle center",
"textfont_size": 20
}
if first:
fig_dict["data"].append(data_dict)
frame["data"].append(data_dict)
fig_dict["frames"].append(frame)
slider_step = {
"args": [
[frame["name"]],
{
"frame": {"duration": 250, "redraw": False},
"mode": "immediate",
"transition": {"duration": 250}
}
],
"label": frame["name"],
"method": "animate"
}
sliders_dict["steps"].append(slider_step)
first = False
fig_dict["layout"]["sliders"] = [sliders_dict]
fig = Figure(fig_dict)
fig.show()